//////////////////////////////////////////////////////////////////////////////////
//	Copyright 2011 by Yosef Grabivker, ryuho@homenetworksoft.com
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//////////////////////////////////////////////////////////////////////////////////

#include <wx/wx.h>
#ifdef LINUX
#include <wx/imaglist.h>
#endif
#include <wx/dir.h>
#include <wx/filename.h> 
#include <sstream>
#include <fstream>
#include "rcmdapp.h"
#include "IP2Country.h"

using namespace std;

CIP2Country::CIP2Country(void)
{
	m_pCountryFlagImage = new wxImageList(18,12);

	if ( m_pCountryFlagImage )
	{
		try
		{
			Load();
		}catch(...)
		{

		}
	}
}

CIP2Country::~CIP2Country(void)
{

}

unsigned short CIP2Country::StringToCode(const char* strCode)
{
	unsigned short wCountryCode(0);

	if ( strCode )
	{
		unsigned char * pwID = (unsigned char *)&wCountryCode;

		pwID[0] = strCode[0];
		pwID[1] = strCode[1];
	}

	return wCountryCode;
}


void CIP2Country::BuidImageList()
{
	wxString strDir( wxGetApp().GetMAPDir() );
	wxDir dir( strDir );

	unsigned int nCount = 0;

	if ( dir.IsOpened() )
	{
		wxFileName fn(strDir, wxT("empty.png"));

		wxImage icnTmp;
		if ( icnTmp.LoadFile(fn.GetFullPath(),   wxBITMAP_TYPE_PNG) )
		{
			m_pCountryFlagImage->Add( icnTmp );
		}



		wxString filename;

		bool cont = dir.GetFirst(&filename, wxT("*.ico"),  wxDIR_FILES);
		while ( cont )
		{
			wxString strCode = filename.Left(2).Upper();
			unsigned short wCountryCode = StringToCode(strCode);

			wxFileName fn(strDir, filename);

			wxImage icnTmp;
			if ( icnTmp.LoadFile( fn.GetFullPath(),  wxBITMAP_TYPE_ICO) )
			{
				int nImageID = m_pCountryFlagImage->Add( icnTmp );
				m_mpCountryToImageID[wCountryCode] = nImageID;
			}

			cont = dir.GetNext(&filename);
		}
	}
}

void CIP2Country::Load()
{
	char szLine[256];

	BuidImageList();

	if ( !m_mpCountryToImageID.empty() )
	{
		wxString strTable = wxT("ip-to-country.csv");
		wxFileName fn( wxGetApp().GetMAPDir(), strTable );
		fstream filestr (fn.GetFullPath().ToAscii(), fstream::in);
		while ( !filestr.getline(szLine, sizeof(szLine)-1).eof() )
		{
			enum cFormat { cFrom, cTo, cCountry, cCountry3, cCountryName };
			int nStage = cFrom;
			IPINFO info;
			
			char * pch;
			pch = strtok (szLine,",\"");

			while (pch != NULL)
			{
				if ( *pch!=0 )
				{
					switch ( nStage )
					{
						case cFrom:
						{
							info.lFrom = atol(pch);
						}
						break;

						case cTo:
						{
							info.lTo = atol(pch);
						}
						break;

						case cCountry:
						{
							info.wCountry = StringToCode( pch );
						}
						break;

						case cCountry3:
						{
							info.strCountryShort = pch;
						}
						break;

						case cCountryName:
						{
							size_t strLen = strlen(pch);

							for(size_t i=1;i<strLen;i++)
							{
								if ( isalpha(pch[i]) )
								{
									pch[i]+='a'-'A'; 
								}
							}

							info.strCountryFull = wxString::FromAscii( pch );
						}
						break;
					}

					nStage++;	
				}

				pch = strtok (NULL, ",\"");
			}

			m_lstIPRange.push_back( info );
		}

		filestr.close();
	}
}

size_t CIP2Country::GetIdx(unsigned long lIP, size_t nFrom, size_t nTo)
{
	size_t st(-1);

	size_t stIDX = (nFrom+nTo)/2;

	const IPINFO& info = m_lstIPRange[ (nFrom+nTo)/2 ];

	if ( lIP>info.lFrom && lIP<=info.lTo )
	{
		return stIDX;
	}

	//not found
	if (nTo-nFrom<=1)
		return -1;

	if ( lIP > info.lTo )
	{
		st = GetIdx( lIP, stIDX, nTo );
	}
	else
	{
		st = GetIdx( lIP, nFrom, stIDX );
	}

	return st;
}


int CIP2Country::GetFlag(unsigned long lIP)
{
	return LookUp(lIP).nImageID;
}

wxString CIP2Country::GetCountry( unsigned long lIP )
{
	return LookUp(lIP).strCountryFull;
}

CIP2Country::IPCACHEINFO	CIP2Country::LookUp(unsigned long lIP)
{
	IPCACHEINFO infoRes;
	infoRes.nImageID = -1;

	if ( m_mpIPCache.size()>10000 )
	{
		m_mpIPCache.erase( m_mpIPCache.begin(), m_mpIPCache.end() );
	}
	else
	{
		IPCACHE::iterator iCur= m_mpIPCache.find( lIP );

		if ( m_mpIPCache.end()!=iCur)
		{
			return iCur->second;
		}
	}

	//DWORD dwSeekTime = GetTickCount();

	//1. Seek ip
	size_t idx = GetIdx(lIP, 0, m_lstIPRange.size()-1 );

	if (-1!=idx)
	{
		const IPINFO& info = m_lstIPRange[idx];

		COUNTRYTOIMAGE::iterator iImage = m_mpCountryToImageID.find( info.wCountry ); 

		if ( iImage != m_mpCountryToImageID.end() )
		{
			IPCACHEINFO entry;
			entry.strCountryFull = info.strCountryShort;
			entry.nImageID = iImage->second;
			m_mpIPCache[lIP] = entry;

			infoRes = entry;
		}
	}

	return infoRes;
}


//////////////////////////////////////////////////////////////////////////////////////////////
